package quartz.job.quartz;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobOperator;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.Properties;

/**
 * Job 的实现类不需要放入到 IOC，可在 web ui 管理(可传入执行参数)
 * Quartz 的 3 个基本要素：
 * * Scheduler：调度器
 * * Trigger：触发器，控制任务什么时候执行
 * * JobDetail & Job：JobDetail 定义的是任务数据，真正的执行逻辑是在 Job 中
 * Scheduler 每次执行都会根据 JobDetail 创建新 Job 实例，规避并发问题
 */
@Slf4j
@RequiredArgsConstructor
@DisallowConcurrentExecution // 不让定时任务并发执行，只有等当前任务完成，下一次任务才会执行
@PersistJobDataAfterExecution // 当 Job 正常执行完后，下一次执行将会得到更新后的值，而不是原始的值
public class Batch extends QuartzJobBean {
    final JobLauncher jobLauncher;
    final JobRegistry jobRegistry;
    final JobOperator jobOperator;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getTrigger().getJobDataMap();
        jobDataMap.put("time", LocalDateTime.now());
        String jobName = String.valueOf(jobDataMap.remove("jobName"));
        Properties properties = new Properties();
        JobParametersBuilder builder = new JobParametersBuilder();
        for (String k : jobDataMap.keySet()) {
            Object v = jobDataMap.get(k);
            if (v instanceof Double) builder.addDouble(k, (Double) v);
            else if (v instanceof Float) builder.addDouble(k, ((Float) v).doubleValue());
            else if (v instanceof Number) builder.addLong(k, (Long) v);
            else if (v instanceof Date) builder.addDate(k, (Date) v);
            else builder.addString(k, String.valueOf(v));
            properties.put(k, String.valueOf(v));
        }
        try { // run spring batch Job
            jobLauncher.run(jobRegistry.getJob(jobName), builder.toJobParameters());
            // jobOperator.start(jobName, PropertiesConverter.propertiesToString(properties));
        } catch (Exception e) {
            throw new JobExecutionException(e);
        }
    }
}